import React from 'react';
import { shallow, mount, render } from 'enzyme';
import Tab from './tab';

describe('A suite test', () => {
    test('判断样式是否存在，css-module也可以测试', () => {
        expect(
            shallow(<Tab />)
                .find('.foo')
                .exists()
        ).toBe(true);
        expect(
            render(<Tab />)
                .children()
                .hasClass('tab')
        ).toBeTruthy();
    });

    // 生成快照，跟上一次的对比，如果有修改则报错(如果修改页面一般注释不用)
    test('生成快照', () => {
        const wrapper = render(<Tab />);
        expect(wrapper).toMatchSnapshot();
    });

    test('props传递是否正确', () => {
        const wrapper = mount(<Tab showTopScreenNum={5} />);
        expect(wrapper.props().showTopScreenNum).toBe(5);
        wrapper.setProps({ showTopScreenNum: 6 });
        expect(wrapper.prop('showTopScreenNum')).toBe(6);
    });

    test('state设置是否正确', () => {
        const wrapper = mount(<Tab />);
        expect(wrapper.find('.show').exists()).toBe(false);
        wrapper.setState({ showDiv: true });
        expect(wrapper.find('.show').exists()).toBe(true);
    });

    // 使用spy替身的时候，在测试用例结束后，要对spy进行restore，不然这个spy会一直存在，并且无法对相同的方法再次进行spy。
    test('测试componentWillReceiveProps 生命周期的调用', () => {
        const WillReceiveProps = jest.spyOn(Tab.prototype, 'componentWillReceiveProps');
        const wrapper = mount(<Tab title="Demo" value={5} />);
        wrapper.setProps({
            showTopScreenNum: 8,
        });
        expect(WillReceiveProps).toHaveBeenCalled();
        WillReceiveProps.mockRestore();
    });

    // class中使用箭头函数来定义方法
    test('测试handleTest 是否可以调用', () => {
        const wrapper = shallow(<Tab />);
        const spyFunction = jest.spyOn(wrapper.instance(), 'handleTest');
        wrapper.instance().handleTest();
        expect(spyFunction).toHaveBeenCalled();
        spyFunction.mockRestore();
    });

    test('测试class 在constructor使用bind来定义方法调用', () => {
        //
        const wrapper = shallow(<Tab />);
        const spyFunction = jest.spyOn(Tab.prototype, 'handleTest2');
        wrapper.instance().handleTest2();
        expect(spyFunction).toHaveBeenCalled();
        spyFunction.mockRestore();
    });

    test('测试定时器', () => {
        jest.useFakeTimers();
        const wrapper = shallow(<Tab />);
        const timeFunction = jest.spyOn(wrapper.instance(), 'setTimeTest');
        const callback = jest.fn();
        wrapper.instance().setTimeTest(callback);
        expect(callback).not.toBeCalled();
        jest.runAllTimers();
        // Now our callback should have been called!
        expect(timeFunction).toHaveBeenCalled();
        expect(callback).toBeCalled();
        expect(callback).toHaveBeenCalledTimes(1);
    });

    test('测试定时器 自己设置时间', () => {
        jest.useFakeTimers();
        const wrapper = shallow(<Tab />);
        const timeFunction = jest.spyOn(wrapper.instance(), 'setInterRun');
        const callback = jest.fn();
        wrapper.instance().setInterRun(callback);
        expect(callback).not.toBeCalled();
        jest.advanceTimersByTime(1000); // 假定1秒以后就会执行
        // Now our callback should have been called!
        expect(callback).toBeCalled();
        expect(timeFunction).toHaveBeenCalled();
        expect(callback).toHaveBeenCalledTimes(1);
        jest.advanceTimersByTime(1000); // 假定2秒以后就会执行
        expect(callback).toHaveBeenCalledTimes(2);
    });

    test('onClick 点击事件测试', () => {
        const clickBtn = jest.fn();
        const wrapper = shallow(<Tab clickBtn={clickBtn} />);
        wrapper.find('.button').simulate('click');
        expect(clickBtn).toBeCalled();
        wrapper.find('.button').simulate('click');
        expect(clickBtn).toHaveBeenCalledTimes(2);
    });

    // 将组件渲染成虚拟DOM对象，只会渲染第一层，子组件将不会被渲染出来
    test('测试 shallow 500次', () => {
        for (let i = 0; i < 500; i++) {
            const nav = shallow(<Tab />);
            expect(nav.find('a').text()).toBe('标题');
        }
    });

    // 静态渲染，将React组件渲染成静态的HTML字符串，返回一个Cheerio的实例对象，可以用来分析组件的html结构
    test('测试render500次', () => {
        for (let i = 0; i < 500; i++) {
            const nav = render(<Tab />);
            expect(nav.find('a').text()).toBe('标题');
        }
    });

    // 完全渲染，它将组件渲染加载成一个真实的DOM节点，用来测试DOM API的交互和组件的生命周期
    test('测试mount500次', () => {
        for (let i = 0; i < 500; i++) {
            const nav = mount(<Tab />);
            expect(nav.find('a').text()).toBe('标题');
        }
    });
});
